-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Allow arbitrary types in dict.pop (3 overloads)
#15297
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
dict.pop (3 overloads)
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Although the primer looks nicer as in #15296, I think this is mostly due to false negatives (see #15296 (comment) and #15296 (comment)) |
|
Reopened due to suggestion of splitting #15296 into 2 steps: (1) convert key to object, (2) investigate the removal of middle overload. |
|
Diff from mypy_primer, showing the effect of this PR on open source code: mongo-python-driver (https://github.com/mongodb/mongo-python-driver)
+ bson/son.py:126: error: Signature of "pop" incompatible with supertype "builtins.dict" [override]
+ bson/son.py:126: note: Superclass:
+ bson/son.py:126: note: @overload
+ bson/son.py:126: note: def pop(self, object, /) -> _Value
+ bson/son.py:126: note: @overload
+ bson/son.py:126: note: def pop(self, object, _Value, /) -> _Value
+ bson/son.py:126: note: @overload
+ bson/son.py:126: note: def [_T] pop(self, object, _T, /) -> _Value | _T
+ bson/son.py:126: note: Subclass:
+ bson/son.py:126: note: def [_T] pop(self, key: _Key, *args: _Value | _T) -> _Value | _T
pylox (https://github.com/sco1/pylox)
+ pylox/containers/array.py:83: note: def pop(self, object, /) -> Any
- pylox/containers/array.py:83: note: def pop(self, Any, /) -> Any
+ pylox/containers/array.py:83: note: def pop(self, object, Any, /) -> Any
- pylox/containers/array.py:83: note: def pop(self, Any, Any, /) -> Any
- pylox/containers/array.py:83: note: def [_T] pop(self, Any, _T, /) -> Any | _T
+ pylox/containers/array.py:83: note: def [_T] pop(self, object, _T, /) -> Any | _T
rotki (https://github.com/rotki/rotki)
+ rotkehlchen/chain/aggregator.py:727: error: Unused "type: ignore" comment [unused-ignore]
django-stubs (https://github.com/typeddjango/django-stubs)
+ django-stubs/http/request.pyi:202: error: Signature of "pop" incompatible with supertype "builtins.dict" [override]
+ django-stubs/http/request.pyi:202: note: Superclass:
+ django-stubs/http/request.pyi:202: note: @overload
+ django-stubs/http/request.pyi:202: note: def pop(self, object, /) -> str
+ django-stubs/http/request.pyi:202: note: @overload
+ django-stubs/http/request.pyi:202: note: def pop(self, object, str, /) -> str
+ django-stubs/http/request.pyi:202: note: @overload
+ django-stubs/http/request.pyi:202: note: def [_T] pop(self, object, _T, /) -> str | _T
+ django-stubs/http/request.pyi:202: note: Subclass:
+ django-stubs/http/request.pyi:202: note: @overload
+ django-stubs/http/request.pyi:202: note: def pop(self, str | bytes, /) -> Never
+ django-stubs/http/request.pyi:202: note: @overload
+ django-stubs/http/request.pyi:202: note: def [_Z] pop(self, str | bytes, str | _Z = ..., /) -> Never
pylint (https://github.com/pycqa/pylint)
+ pylint/config/arguments_provider.py:54: error: Incompatible types in "yield" (actual type "tuple[None, list[tuple[str, dict[str, str | bool | int | Pattern[str] | Iterable[str | int | Pattern[str]] | type[_CallbackAction] | Callable[[Any], Any] | Callable[[Any, Any, Any, Any], Any] | None], Any]]]", expected type "tuple[str, list[tuple[str, dict[str, str | bool | int | Pattern[str] | Iterable[str | int | Pattern[str]] | type[_CallbackAction] | Callable[[Any], Any] | Callable[[Any, Any, Any, Any], Any] | None], Any]]] | tuple[None, dict[str, list[tuple[str, dict[str, str | bool | int | Pattern[str] | Iterable[str | int | Pattern[str]] | type[_CallbackAction] | Callable[[Any], Any] | Callable[[Any, Any, Any, Any], Any] | None], Any]]]]") [misc]
+ pylint/config/arguments_provider.py:54: note: Error code "misc" not covered by "type: ignore" comment
+ pylint/config/arguments_provider.py:54: error: Unused "type: ignore" comment [unused-ignore]
scrapy (https://github.com/scrapy/scrapy)
+ scrapy/utils/datatypes.py:98: error: Signature of "pop" incompatible with supertype "builtins.dict" [override]
+ scrapy/utils/datatypes.py:98: note: Superclass:
+ scrapy/utils/datatypes.py:98: note: @overload
+ scrapy/utils/datatypes.py:98: note: def pop(self, object, /) -> Any
+ scrapy/utils/datatypes.py:98: note: @overload
+ scrapy/utils/datatypes.py:98: note: def pop(self, object, Any, /) -> Any
+ scrapy/utils/datatypes.py:98: note: @overload
+ scrapy/utils/datatypes.py:98: note: def [_T] pop(self, object, _T, /) -> Any | _T
+ scrapy/utils/datatypes.py:98: note: Subclass:
+ scrapy/utils/datatypes.py:98: note: def [AnyStr: (str, bytes)] pop(self, key: AnyStr, *args: Any) -> Any
discord.py (https://github.com/Rapptz/discord.py)
+ discord/ui/view.py:932: error: Unused "type: ignore" comment [unused-ignore]
steam.py (https://github.com/Gobot1234/steam.py)
- steam/ext/commands/utils.py:52: note: def pop(self, str, /) -> _VT
+ steam/ext/commands/utils.py:52: note: def pop(self, object, /) -> _VT
- steam/ext/commands/utils.py:52: note: def pop(self, str, _VT, /) -> _VT
+ steam/ext/commands/utils.py:52: note: def pop(self, object, _VT, /) -> _VT
- steam/ext/commands/utils.py:52: note: def [_T] pop(self, str, _T, /) -> _VT | _T
+ steam/ext/commands/utils.py:52: note: def [_T] pop(self, object, _T, /) -> _VT | _T
- steam/ext/commands/utils.py:52: note: def pop(self, str, /) -> _VT
+ steam/ext/commands/utils.py:52: note: def pop(self, Any, /) -> _VT
- steam/ext/commands/utils.py:52: note: def pop(self, str, _VT, /) -> _VT
+ steam/ext/commands/utils.py:52: note: def pop(self, Any, _VT, /) -> _VT
- steam/ext/commands/utils.py:52: note: def [_T] pop(self, str, _T, /) -> _VT | _T
+ steam/ext/commands/utils.py:52: note: def [_T] pop(self, Any, _T, /) -> _VT | _T
operator (https://github.com/canonical/operator)
- ops/_private/harness.py:2645: error: No overload variant of "pop" of "dict" matches argument types "str", "None" [call-overload]
- ops/_private/harness.py:2645: note: Possible overload variants:
- ops/_private/harness.py:2645: note: def pop(self, int, /) -> dict[str, Any]
- ops/_private/harness.py:2645: note: def pop(self, int, dict[str, Any], /) -> dict[str, Any]
- ops/_private/harness.py:2645: note: def [_T] pop(self, int, _T, /) -> dict[str, Any] | _T
|
|
Why are you sometimes using The primer output is not very convincing. Lots of churn, and only one weird case – which could arguably point to a real problem or at least weird typing – and one case that could be solved by using I remain unconvinced that this change is actually beneficial to our users, although I won't argue if other maintainers feel differently. |
|
I am using Let me do a test of only removing the second overload without changing the annotation. I have a suspicion that these two things may be entangled, so disentangling them into 2 separate PRs may not be appropriate after all. |
|
I don't have a strong opinion on
This change would be very beneficial to ty users. ty attempts to do type narrowing in a stricter, more principled way than other type checkers, but this causes false positives when encountering methods that are annotated like this in typeshed, so I would be in favour of landing something along these lines. For example, mypy's behaviour here is as follows: def f(x: object):
if isinstance(x, dict):
reveal_type(x) # revealed: dict[Any, Any]
x.pop("foo") # no errorwhereas ty's behaviour is: def f(x: object):
if isinstance(x, dict):
reveal_type(x) # revealed: Top[dict[Unknown, Unknown]]
x.pop("foo") # Argument to bound method `pop` is incorrect: Expected `Never`, found `Literal["foo"]`
Our reasoning for using |
|
Cf. python/typing#2154 for a potential future "best of both worlds" solution. If this would be beneficial for ty, this has my blessing (for now). |
|
Actually, I think we should use |
|
That was my rationale for using This is the default implementation: https://github.com/python/cpython/blob/3c9c3d33cbdef257526871cbc12e93635026f5d6/Lib/_collections_abc.py#L929-L941 def pop(self, key, default=__marker):
'''D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
If key is not found, d is returned if given, otherwise KeyError is raised.
'''
try:
value = self[key]
except KeyError:
if default is self.__marker:
raise
return default
else:
del self[key]
return valueIt will catch But I am easily convinced that there are |
Fixes #15271
new overloads: